package dao

import (
	"context"
	"fmt"
	"strconv"

	"user_srv/basic/config"
	__ "user_srv/basic/userproto"
	"user_srv/handler/models"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gorm.io/gorm"
)

// GetSecurityEventsProto 获取安全事件列表（Proto接口）
func GetSecurityEventsProto(ctx context.Context, req *__.GetSecurityEventsReq) (*__.GetSecurityEventsResp, error) {
	// 参数验证
	if req.Pagination == nil {
		return nil, status.Errorf(codes.InvalidArgument, "pagination is required")
	}

	// 规范化分页参数
	page := req.Pagination.Page
	if page <= 0 {
		page = 1
	}
	pageSize := req.Pagination.PageSize
	if pageSize <= 0 {
		pageSize = 20
	} else if pageSize > 100 {
		pageSize = 100
	}

	// 调用现有方法
	events, _, err := GetSecurityEvents(ctx, req.EventType, req.Severity, req.Status, uint(req.UserId), int(page), int(pageSize))
	if err != nil {
		return nil, status.Errorf(codes.Internal, "failed to get security events: %v", err)
	}

	// 转换为proto响应格式
	protoEvents := make([]*__.SecurityEvent, 0, len(events))
	for _, event := range events {
		protoEvents = append(protoEvents, convertSecurityEventToProto(event))
	}

	// 计算总页数
	return &__.GetSecurityEventsResp{
		Events: protoEvents,
	}, nil
}

// convertSecurityEventToProto 将安全事件模型转换为proto格式
func convertSecurityEventToProto(event *models.SecurityEvent) *__.SecurityEvent {
	return &__.SecurityEvent{
		Id:         uint64(event.ID),
		UserId:     uint64(event.UserID),
		EventType:  event.Type,
		Details:    event.Description,
		IpAddress:  event.IpAddress,
		DeviceInfo: event.Location,
		IsRisky:    event.Severity == "high" || event.Severity == "danger",
		CreatedAt:  event.Timestamp,
		UpdatedAt:  event.UpdatedAt.Format("2006-01-02 15:04:05"),
	}
}

// GetSecurityEvents 获取安全事件列表
func GetSecurityEvents(ctx context.Context, eventType, severity, status string, userID uint, page, pageSize int) ([]*models.SecurityEvent, int64, error) {
	var events []*models.SecurityEvent
	var total int64

	query := config.DB.Model(&models.SecurityEvent{})

	// 添加筛选条件
	if eventType != "" {
		query = query.Where("type = ?", eventType)
	}

	if severity != "" {
		query = query.Where("severity = ?", severity)
	}

	if status != "" {
		query = query.Where("status = ?", status)
	}

	if userID != 0 {
		query = query.Where("user_id = ?", userID)
	}

	// 计算总数
	query.Count(&total)

	// 分页查询
	offset := (page - 1) * pageSize
	err := query.Order("timestamp DESC").Offset(offset).Limit(pageSize).Find(&events).Error

	return events, total, err
}

// GetSecurityEventProto 获取安全事件详情（Proto接口）
func GetSecurityEventProto(ctx context.Context, req *__.GetSecurityEventReq) (*__.GetSecurityEventResp, error) {
	// 参数验证
	if req.EventId == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "event id is required")
	}

	// 调用现有方法
	event, err := GetSecurityEvent(ctx, int(req.EventId))
	if err != nil {
		return nil, status.Errorf(codes.NotFound, "security event not found: %v", err)
	}

	return &__.GetSecurityEventResp{Event: convertSecurityEventToProto(event)}, nil
}

// GetSecurityEvent 获取单个安全事件详情
func GetSecurityEvent(ctx context.Context, id int) (*models.SecurityEvent, error) {
	var event models.SecurityEvent
	err := config.DB.Where("event_id = ?", id).First(&event).Error
	if err != nil {
		return nil, err
	}

	return &event, nil
}

// HandleSecurityEventProto 处理安全事件（Proto接口）
func HandleSecurityEventProto(ctx context.Context, req *__.HandleSecurityEventReq) (*__.HandleSecurityEventResp, error) {
	// 参数验证
	if req.EventId == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "event id is required")
	}

	// 调用现有方法（根据原函数签名调整参数）
	event, err := HandleSecurityEvent(ctx, strconv.FormatUint(req.EventId, 10), true, req.Notes, req.Handler)
	if err != nil {
		return nil, status.Errorf(codes.NotFound, "failed to handle security event: %v", err)
	}

	return &__.HandleSecurityEventResp{
		Event:   convertSecurityEventToProto(event),
		Success: true,
	}, nil
}

// HandleSecurityEvent 处理安全事件
func HandleSecurityEvent(ctx context.Context, id string, handled bool, remark string, handler string) (*models.SecurityEvent, error) {
	var event models.SecurityEvent
	if err := config.DB.Where("event_id = ?", id).First(&event).Error; err != nil {
		return nil, err
	}

	// 更新事件状态
	if handled {
		event.Status = "handled"
	} else {
		event.Status = "ignored"
	}

	event.Remark = remark
	event.Handler = handler

	if err := config.DB.Save(&event).Error; err != nil {
		return nil, err
	}

	return &event, nil
}

// GetSecuritySettingsProto 获取安全设置（Proto接口）
func GetSecuritySettingsProto(ctx context.Context, req *__.GetSecuritySettingsReq) (*__.GetSecuritySettingsResp, error) {
	// 参数验证
	if req.UserId == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "user id is required")
	}

	// 调用现有方法
	settings, err := GetSecuritySettings(ctx)
	if err != nil {
		return nil, status.Errorf(codes.NotFound, "security settings not found: %v", err)
	}

	// 转换为proto响应格式
	protoSettings := &__.SecuritySettings{
		UserId:        uint64(settings.ID),
		TwoFactorAuth: settings.RemoteLoginVerify,
		LoginHistory:  settings.LoginFailureLock,
		AlertTypes:    []string{}, // 可根据实际需求填充
		UpdatedAt:     settings.UpdatedAt.Format("2006-01-02 15:04:05"),
	}

	return &__.GetSecuritySettingsResp{Settings: protoSettings}, nil
}

// GetSecuritySettings 获取安全设置
func GetSecuritySettings(ctx context.Context) (*models.SecuritySetting, error) {
	var settings models.SecuritySetting
	// 通常安全设置只有一条记录
	err := config.DB.First(&settings).Error
	if err != nil {
		// 如果没有记录，返回默认设置
		if err == gorm.ErrRecordNotFound {
			return &models.SecuritySetting{
				RemoteLoginVerify:          true,
				LoginFailureLock:           true,
				LargeTransactionVerify:     true,
				AbnormalTransactionControl: true,
				DailyTransactionLimit:      "100000",
				SensitiveOperationLog:      true,
				RegularSecurityScan:        true,
			}, nil
		}
		return nil, err
	}

	return &settings, nil
}

// UpdateSecuritySettingsProto 更新安全设置（Proto接口）
func UpdateSecuritySettingsProto(ctx context.Context, req *__.UpdateSecuritySettingsReq) (*__.UpdateSecuritySettingsResp, error) {
	// 参数验证
	if req.Settings == nil {
		return nil, status.Errorf(codes.InvalidArgument, "settings data is required")
	}

	// 创建模型对象
	securitySettings := &models.SecuritySetting{
		RemoteLoginVerify:          req.Settings.TwoFactorAuth,
		LoginFailureLock:           req.Settings.LoginHistory,
		LargeTransactionVerify:     false, // 根据实际需求设置
		AbnormalTransactionControl: false, // 根据实际需求设置
		SensitiveOperationLog:      len(req.Settings.AlertTypes) > 0,
		RegularSecurityScan:        len(req.Settings.AlertTypes) > 0,
	}

	// 调用现有方法
	updatedSettings, err := UpdateSecuritySettings(ctx, securitySettings)
	if err != nil {
		return nil, status.Errorf(codes.Internal, "failed to update security settings: %v", err)
	}

	// 转换为proto响应格式
	protoSettings := &__.SecuritySettings{
		UserId:        uint64(updatedSettings.ID),
		TwoFactorAuth: updatedSettings.RemoteLoginVerify,
		LoginHistory:  updatedSettings.LoginFailureLock,
		AlertTypes:    req.Settings.AlertTypes,
		UpdatedAt:     updatedSettings.UpdatedAt.Format("2006-01-02 15:04:05"),
	}

	return &__.UpdateSecuritySettingsResp{Settings: protoSettings}, nil
}

// UpdateSecuritySettings 更新安全设置
func UpdateSecuritySettings(ctx context.Context, settings *models.SecuritySetting) (*models.SecuritySetting, error) {
	var existingSettings models.SecuritySetting

	// 查找现有设置
	err := config.DB.First(&existingSettings).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			// 创建新设置
			return settings, config.DB.Create(settings).Error
		}
		return nil, err
	}

	// 更新现有设置
	settings.ID = existingSettings.ID
	return settings, config.DB.Save(settings).Error
}

// GetSecurityStatusProto 获取安全状态概览（Proto接口）
func GetSecurityStatusProto(ctx context.Context) (*__.SecurityStatus, error) {
	status, err := GetSecurityStatus(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get security status: %v", err)
	}

	return &__.SecurityStatus{
		SecurityScore:    int32(status.SecurityScore),
		TodayEvents:      int32(status.TodayEvents),
		RiskUsers:        int32(status.RiskUsers),
		RiskTransactions: int32(status.RiskTransactions),
		IncomeRate:       status.IncomeRate,
		EventTrend:       status.EventTrend,
		LastScanTime:     status.LastScanTime,
	}, nil
}

// GetSecurityStatus 获取安全状态概览
func GetSecurityStatus(ctx context.Context) (*models.SecurityStatus, error) {
	var status models.SecurityStatus
	// 通常安全状态只有一条记录
	err := config.DB.First(&status).Error
	if err != nil {
		// 如果没有记录，返回默认状态
		if err == gorm.ErrRecordNotFound {
			return &models.SecurityStatus{
				SecurityScore:    85,
				TodayEvents:      12,
				RiskUsers:        3,
				RiskTransactions: 5,
				IncomeRate:       2.5,
				EventTrend:       "decreasing",
			}, nil
		}
		return nil, err
	}

	return &status, nil
}

// GetUserSecurityInfoProto 获取用户安全信息（Proto接口）
func GetUserSecurityInfoProto(ctx context.Context, req *__.GetUserSecurityInfoReq) (*__.GetUserSecurityInfoResp, error) {
	// 参数验证
	if req.UserId == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "user id is required")
	}

	userInfo, err := GetUserSecurityInfo(ctx, uint(req.UserId))
	if err != nil {
		return nil, status.Errorf(codes.NotFound, "user security info not found: %v", err)
	}

	return &__.GetUserSecurityInfoResp{
		UserInfo: &__.UserSecurityInfo{
			UserId:            uint64(userInfo.UserID),
			Username:          userInfo.Username,
			RiskScore:         int32(userInfo.RiskScore),
			LastLoginTime:     userInfo.LastLoginTime,
			LastLoginIp:       userInfo.LastLoginIp,
			LastLoginLocation: userInfo.LastLoginLocation,
			IsVerified:        userInfo.IsVerified,
			HasBindPhone:      userInfo.HasBindPhone,
			HasBindEmail:      userInfo.HasBindEmail,
			RiskLevel:         userInfo.RiskLevel,
		},
	}, nil
}

// GetUserSecurityInfo 获取用户安全信息
func GetUserSecurityInfo(ctx context.Context, userID uint) (*models.UserSecurityInfo, error) {
	var userInfo models.UserSecurityInfo
	err := config.DB.Where("user_id = ?", userID).First(&userInfo).Error
	if err != nil {
		return nil, err
	}

	return &userInfo, nil
}

// GetRiskUsersProto 获取风险用户列表（Proto接口）
func GetRiskUsersProto(ctx context.Context, req *__.GetRiskUsersReq) (*__.GetRiskUsersResp, error) {
	// 规范化分页参数
	page := req.Page
	if page <= 0 {
		page = 1
	}
	pageSize := req.PageSize
	if pageSize <= 0 {
		pageSize = 20
	} else if pageSize > 100 {
		pageSize = 100
	}

	users, total, err := GetRiskUsers(ctx, req.RiskLevel, int(page), int(pageSize))
	if err != nil {
		return nil, status.Errorf(codes.Internal, "failed to get risk users: %v", err)
	}

	// 转换为proto响应格式
	protoUsers := make([]*__.UserSecurityInfo, 0, len(users))
	for _, user := range users {
		protoUsers = append(protoUsers, &__.UserSecurityInfo{
			UserId:            uint64(user.UserID),
			Username:          user.Username,
			RiskScore:         int32(user.RiskScore),
			LastLoginTime:     user.LastLoginTime,
			LastLoginIp:       user.LastLoginIp,
			LastLoginLocation: user.LastLoginLocation,
			IsVerified:        user.IsVerified,
			HasBindPhone:      user.HasBindPhone,
			HasBindEmail:      user.HasBindEmail,
			RiskLevel:         user.RiskLevel,
		})
	}

	return &__.GetRiskUsersResp{
		Users: protoUsers,
		Total: total,
	}, nil
}

// GetRiskUsers 获取风险用户列表
func GetRiskUsers(ctx context.Context, riskLevel string, page, pageSize int) ([]*models.UserSecurityInfo, int64, error) {
	var users []*models.UserSecurityInfo
	var total int64

	query := config.DB.Model(&models.UserSecurityInfo{})

	// 添加风险等级筛选
	if riskLevel != "" {
		query = query.Where("risk_level = ?", riskLevel)
	}

	// 计算总数
	query.Count(&total)

	// 分页查询
	offset := (page - 1) * pageSize
	err := query.Order("risk_score DESC").Offset(offset).Limit(pageSize).Find(&users).Error

	return users, total, err
}

// CreateSecurityEvent 创建安全事件
func CreateSecurityEvent(ctx context.Context, event *models.SecurityEvent) error {
	return config.DB.Create(event).Error
}

// UpdateUserSecurityInfo 更新用户安全信息
func UpdateUserSecurityInfo(ctx context.Context, userInfo *models.UserSecurityInfo) error {
	return config.DB.Save(userInfo).Error
}
